package org.sky.framework.soap;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * soap 客户端
 * 
 * @author gaofu
 *
 */
public class SoapClient {
	private final static Logger logger = LoggerFactory.getLogger(SoapClient.class);

	/**
	 * 发送soap请求, 并封装响应内容
	 * 
	 * @param wsdlUrl  请求Webservice地址(?wsdl)
	 * @param request  请求内容
	 * @param response 响应内容
	 * @throws Exception
	 */
	public static <QH, QB, PH, PB> void execute(String wsdlUrl, SoapEntity<QH, QB> request, SoapEntity<PH, PB> response)
			throws Exception {
		logger.info("发送地址: " + wsdlUrl);
		String xml = request.soapXml();
		logger.info("发送内容: " + xml);
		String responseXml = httpPostXml(wsdlUrl, xml);
		logger.info("接收内容: " + responseXml);
		//
		response.init(responseXml);
		// 判断是否有错误消息
		if (response.getFault() == null) {
			logger.info("接口正常! ");
		} else {
			SoapFault fault = response.getFault();
			StringBuilder err = new StringBuilder();
			err.append("接口错误: ");
			err.append(fault.getFaultcodeInfo());
			err.append(": {'faultcode' : '");
			err.append(fault.getFaultcode());
			err.append("', 'faultstring' : '");
			err.append(fault.getFaultstring());
			err.append("'}");
			logger.info(err.toString());
		}
	}

	/**
	 * http post xml请求
	 * 
	 * @param url
	 * @param xml
	 * @return
	 * @throws IOException
	 */
	private static String httpPostXml(String url, String xml) throws Exception {
		String charset = "UTF-8";
		StringBuilder result = new StringBuilder();
		OutputStreamWriter out = null;
		boolean isOutFlushed = false;
		boolean isOutClosed = false;
		BufferedReader reader = null;
		boolean isReaderClosed = false;
		try {
			URL Url = new URL(url);
			HttpURLConnection con = (HttpURLConnection) Url.openConnection();
			// 设置连接主机服务器超时时间：15_000毫秒
			con.setConnectTimeout(15000);
			// 设置读取主机服务器返回数据超时时间：300_000毫秒
			con.setReadTimeout(300000);
			// 默认值为：false，当向远程服务器传送数据/写数据时，需要设置为true
			con.setDoOutput(true);
			// 默认值为：true，当前向远程服务读取数据时，设置为true，该参数可有可无
			con.setDoInput(true);
			// 设置连接请求方式
			con.setRequestMethod("POST");
			con.setRequestProperty("Content-Type", "text/xml; charset=" + charset);
			out = new OutputStreamWriter(con.getOutputStream(), charset);
			out.write(xml);
			out.flush();
			isOutFlushed = true;
			out.close();
			isOutClosed = true;
			String line = null;
			reader = new BufferedReader(new InputStreamReader(con.getInputStream(), charset));
			while ((line = reader.readLine()) != null) {
				result.append(line.replaceAll("[\\t\\n\\r]", ""));
			}
			reader.close();
			isReaderClosed = true;
		} catch (Exception e) {
			logger.error("接口异常", e);
			if (out != null) {
				try {
					if (!isOutFlushed) {
						out.flush();
					}
				} catch (IOException ex) {
					logger.error("out.flush异常", ex);
				}
				try {
					if (!isOutClosed) {
						out.close();
					}
				} catch (IOException ex) {
					logger.error("out.close异常", ex);
				}
			}
			if (reader != null) {
				try {
					if (!isReaderClosed) {
						reader.close();
					}
				} catch (IOException ex) {
					logger.error("reader.close异常", ex);
				}
			}
			throw e;
		}
		return result.toString();
	}

}
